/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.dao.hibernate;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.activequant.dao.IStoreDao;
import org.activequant.util.exceptions.DaoException;
import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * StoreDao extends HibernateDaoSupport implements IStoreDao.<br/>
 * Defines the Adapter nested class. Holds the following inherited variable:
 * <ul>
 * <li>hibernateTemplate(HibernateTemplate)</li>
 * </ul>
 * <br>
 * <b>History:</b><br>
 *  - [07.01.2008] Created (Erik Nijkamp)<br>
 *
 *  @author Erik Nijkamp
 */
public class StoreDao extends HibernateDaoSupport implements IStoreDao {
	/**
	 * Static, nested class. Holds the following associated variables:
	 * <ul>
	 * <li>name(String)</li>
	 * <li>object(byte[])</li>
	 * </ul>
	 * @author Dimitar
	 *
	 */
	public static class Adapter {
		/**
		 * private String name;
		 */
		private String name;
		/**
		 * private byte[] object;
		 */
		private byte[] object;
		/**
		 * An empty Adapter constructor
		 */
		public Adapter() {
			
		}
		/**
		 * Constructs an Adapter using the given name(String) and object(byte[]) to set its associated
		 * name(String) and object(byte[]).
		 * @param name
		 * @param object
		 */
		public Adapter(String name, byte[] object) {
			this.name = name;
			this.object = object;
		}
		/**
		 * returns the associated name(String)
		 * @return
		 */
		public String getName() {
			return name;
		}
		/**
		 * sets the associated name(String) with the given name(String)
		 * @param name
		 */
		public void setName(String name) {
			this.name = name;
		}
		/**
		 * returns the associated object(byte[])
		 * @return
		 */
		public byte[] getObject() {
			return object;
		}
		/**
		 * sets the associated object(byte[]) with the given object(byte[])
		 * @param object
		 */
		public void setObject(byte[] object) {
			this.object = object;
		}
	}
	/**
	 * An empty StoreDao(extends HibernateDaoSupport implements IStoreDao) constructor
	 */
	public StoreDao() {
	}
	/**
	 * constructs a StoreDao(extends HibernateDaoSupport implements IStoreDao) using the given sessionFactory(SessionFactory) 
	 * to set its Hibernate SessionFactory and create/initialize the inherited hibernateTemplate(HibernateTemplate)
	 * @param sessionFactory
	 */
	public StoreDao(SessionFactory sessionFactory) {
		setSessionFactory(sessionFactory);
	}
	/**
	 * Returns the number(int)/count of records in the "store" table
	 */
    @SuppressWarnings("unchecked")
	public int count() {
		try {
	        List<Long> list = getHibernateTemplate().find("SELECT count(*) FROM store");
	        Integer count = list.get(0).intValue();
	        return count.intValue();
		} catch (Exception e) {
			throw new DaoException(e);
		}
    }
    /**
     * Deletes the Adapter(Store) persistent instance whose name(String) matches the given name(String)
     */
	public void delete(String name) throws DaoException {
		try {
			Adapter adapter = (Adapter) getHibernateTemplate().get(Adapter.class, name);
			getHibernateTemplate().delete(adapter);
		} catch (Exception e) {
			throw new DaoException(e);
		}		
	}
	/**
	 * protected final int BATCH_SIZE = 100;
	 */
	protected final int BATCH_SIZE = 100;
	/**
	 * Deletes all Adapter(Store) persistent instances in batches of BATCH_SIZE(100) at a time.
	 */
	public void deleteAll() throws DaoException {
		try {
			/* delete subsets by hand cause:
			 * - loadAll() throws OutOfMemoryException
			 * - bulk-delete ignores cascading deletes
			 */
			getHibernateTemplate().execute(new HibernateCallback() { 
				public Object doInHibernate(Session session) throws HibernateException, SQLException {
					ScrollableResults objects = session.createCriteria(Adapter.class).setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
					int count = 0;
					while(objects.next()) {
				    	Object entity = objects.get(0);
			        	session.delete(entity);
				    	if(++count % BATCH_SIZE == 0) {
				        	// flush a batch of updates and release memory
				    		session.flush();
				        	session.clear();
				    	}
					}
					return null;
				}
			});
		} catch (Exception e) {
			throw new DaoException(e);
		}		
	}
	/**
	 * <strong>1.</strong> Finds the adapter(Adapter)/(store) whose name(String) matches the given name(String)<br/>
	 * <strong>2.</strong> Reads and returns an object(Serializable) from the object(byte[]) of that adapter(Adapter).
	 */
	public Serializable find(String name) throws DaoException {
		try {			
			Adapter adapter = (Adapter) getHibernateTemplate().get(Adapter.class, name);
			ByteArrayInputStream in = new ByteArrayInputStream(adapter.getObject());
			ObjectInputStream stream = new ObjectInputStream(in);			
			Serializable out = (Serializable) stream.readObject();
			stream.close();
			return out;
		} catch (Exception e) {
			throw new DaoException(e);
		}
	}
	/**
	 * returns null
	 */
	@SuppressWarnings("unchecked")
	public Serializable[] findAll() {
		try {
			return null;
		} catch (Exception e) {
			throw new DaoException(e);
		}
	}
	/**
	 * <strong>1.</strong> Creates an adapter(Adapter)/(store) using the given name(String) to set its associated name(String).<br/>
	 * The given entity(Serializable) is serialized and used to set its object(byte[]).<br/>
	 * <strong>2.</strong> Saves/updates that adapter(Adapter) instance and returns the given entity(Serializable).
	 */
	public Serializable update(String name, Serializable entity) throws DaoException {
		try {
			// convert to byte array
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			ObjectOutputStream stream = new ObjectOutputStream(out);
			stream.writeObject(entity);
			stream.close();
			
			// store
			byte[] object = out.toByteArray();
			Adapter adapter = new Adapter(name, object);
			getHibernateTemplate().saveOrUpdate(adapter);
			
			return entity;
		} catch(Exception e) {
			throw new DaoException(e);
		}
	}

}
